import requests,json

import calendar
import datetime
from dateutil.relativedelta import relativedelta
import pandas as pd

def ja_db(dc ,act='get',host=None):
    """ http读写数据库 
    """
    if host is None:
        host='oq-upinfo.17121.top:2028'
    tpl = "http://{}/jsonapi/{}"
    url=tpl.format(host,act)
    data = json.dumps(dc,   default=datetime.datetime.isoformat)
    #--获取账号信息
    res_obj = requests.post(url ,data=data,timeout=25)#不能发送中文
    if res_obj.status_code != 200:
        logger.warning('访问 %s 服务错误 【%s】  / %s'%(url, res_obj.status_code, res_obj.text))
    #print(res_obj.text )
    dat_dc = json.loads(res_obj.text)
    return dat_dc 


class 补考勤报告():
    """  通过类完成
* 勤假记录读取，
* 对照出勤表完成  缺勤对照
* 计算出补卡记录


公出需要计算成  班次加入到考勤记录

    """
    one = -1  # 首次运行
    res = {}  # 资源
    
    def _mkQuerDate(self,year:int,mon:int):
        """  创建对应月份的日期范围精确到日
        args:
            year (int):年份
            mon (int): 月份
        returns:
            list (str): ["2000-01-01"，"2000-01-31"]
        """
        # 获取该月的第一天
        first_day = f"{year}-{mon:02d}-01"
        
        # 获取该月的最后一天
        _, last_day_num = calendar.monthrange(year, mon)
        last_day = f"{year}-{mon:02d}-{last_day_num:02d}"
        
        return [first_day, last_day]
        
    def _mkQueryData(self,name:str,dayFirst:str,dayLast:str):
        """ 返回查询 结构的json  占位替换
            args:
                name:str
                dayFirst:str
                dayLast:str
                
            returns:
        """
        jdata={
    "oa/T_USER@用户": {
        "@column": "ID,NAME,DEFAULTDEPARTMENT.部门id,TELEPHONE.手机",
        "NAME": name,
        "@limit": 1
    },   
    "oa/TLK_ATTENDANCEDETAIL@补考勤": {
        "AUTHOR|": "oa/T_USER@用户.ID",
        "ITEM_ATTDATE&": f">={dayFirst},<={dayLast}",
        "@order": "-CREATED",
        "@column": "ITEM_ATTDATE, FORMNAME,AUTHOR,CREATED"
    },
    "oa/TLK_APPLY_LEAVE@请假": {
        "AUTHOR|": "oa/T_USER@用户.ID",
        "ITEM_LEAVE_T&": f">={dayFirst},<={dayLast}",
        "@order": "-CREATED",
        "@column": "AUTHOR, ITEM_START_T.开始时间,ITEM_LEAVE_T.结束时间,ITEM_LEAVE_R.理由,ITEM_APPLICANT,CREATED"
    },
    "oa/TLK_BUSINESS_PUBLIC_TRIP@公出": {
        "AUTHOR|": "oa/T_USER@用户.ID",
        "ITEM_TRAVEL_OT&":  f">={dayFirst},<={dayLast}",
        "@order": "-CREATED",
        "@column": "AUTHOR,ITEM_TRAVEL_ST,ITEM_TRAVEL_OT,ITEM_TRAVEL_R.理由, ITEM_TRAVEL_CITY.公出城市, FORMNAME.模块,STATELABELINFO,CREATED",
        "#url": "http://127.0.0.1:2028/jsonapi/get"
    },
        "kq/USERINFO@考情信息": {
        "@column": "BADGENUMBER.用户id,NAME,USERID.考勤id,DEFAULTDEPTID",
        "NAME": name,
        "@limit": 1
    },
    "kq/CHECKINOUT@考情记录": {
        "@column": "USERID.考勤id,CHECKTIME",
        "USERID|": "kq/USERINFO@考情信息.考勤id",
        "CHECKTIME&": f">={dayFirst},<={dayLast}",
        "@order": "-CHECKTIME"
    }
}
        
        return jdata
        
    def _时间判断v1(self,str4time:str)->str:
        """ 根据给的日期字符串判断 是那个时间段打卡
            含10:30之前都算上班
            含17:00之后都算下班
            11:30到13:30:00 算中午打卡
        args:
            str4time: "2025-11-11 08:00:00"
        returns:
            str:
                - "上班"
                - "下班"
                - "中午"
                - "未知"
                """
        te = str4time[11:]
        if te<="10:30:00":
            return "早上"
        if te>="17:00:00":
            return "晚上"
        if te<"13:30:00" and te>"10:30:00" :
            return "中午"
        return "未知"

    def _标记一行(self,r):
        """  对日期和类型打标记  
        args:
            r dict:
        """
        #print(r['CHECKTIME'])
        d = datetime.datetime.strptime(r['CHECKTIME'], "%Y-%m-%d %H:%M:%S")
        r['时间日期'] = d 
        r['星期'] = d.weekday()+1
        #r['月份'] = d.month 
        r['日期'] = r['CHECKTIME'][:10]
        r['时间'] = r['CHECKTIME'][11:]
        r['早中晚'] = self._时间判断v1(r['CHECKTIME'])
        r['班次'] = '空'
        
        return r 

    def _更新班次(self,df):
        """ 更新班次 为 【上班，下班，中午上，中午下】其中一个 """
        # 中午上
        noon_records = df[df['早中晚'] == '中午']
        max_time_indices = noon_records.groupby('日期')['时间日期'].idxmax()
        df.loc[max_time_indices, '班次'] = "中午上"
        # 中午下
        noon_records = df[df['早中晚'] == '中午']
        min_time_indices = noon_records.groupby('日期')['时间日期'].idxmin()
        df.loc[min_time_indices, '班次'] = "中午下"
        
        # 上班
        noon_records = df[df['早中晚'] == '早上']
        min_time_indices = noon_records.groupby('日期')['时间日期'].idxmin()
        df.loc[min_time_indices, '班次'] = "上班"
        
        # 下班
        noon_records = df[df['早中晚'] == '晚上']
        max_time_indices = noon_records.groupby('日期')['时间日期'].idxmax()
        df.loc[max_time_indices, '班次'] = "下班"
        

    def _出勤表v1(self,year:int,mon:int):
        """
        args:
            year:int
            mon:int
        returns:
            list : [{'日期': '2024-03-03', '班次': '早'},]
        """
        
        sdate = datetime.datetime (year,mon,1)
        edate =  sdate +  relativedelta(months=1)  + datetime.timedelta(days=-1)
        r = []
        tdate = sdate
        for i in range (0,calendar.monthrange( sdate.year,sdate.month )[1]):
            #
            weekday = tdate.weekday() + 1
            # 跳过周末
            if  weekday in [7]:
                tdate = tdate +datetime.timedelta(days=1)
                continue
            r.append({"日期":tdate.strftime("%Y-%m-%d"),"阶段":"上班","星期":str(weekday)})
            r.append({"日期":tdate.strftime("%Y-%m-%d"),"阶段":"中午上","星期":str(weekday)})
            r.append({"日期":tdate.strftime("%Y-%m-%d"),"阶段":"中午下","星期":str(weekday)})
            r.append({"日期":tdate.strftime("%Y-%m-%d"),"阶段":"下班","星期":str(weekday)})
            tdate = tdate +datetime.timedelta(days=1)            
        return r
    
    def getJqData(self,name:str,mon:int,year:int):
        """  """
        """   获取假勤 4项记录 内部"""
        # 开始和结束日期
        sdDate = self._mkQuerDate(year,mon)
        vn = self._mkQueryData(name,sdDate[0], sdDate[1])
        # 查询
        vd = ja_db(  vn )
        
        return vd
        
    def getJqDataV2(self,name:str,mon:int,year:int):
        """   获取假勤 4项记录 内部"""
        # 开始和结束日期
        sdDate = self._mkQuerDate(year,mon)
        vn = self._mkQueryData(name,sdDate[0], sdDate[1])
        # 查询
        return chekdf
    
    def getJqTab(self,name:str,mon:int,year:int):
        """ 获取假勤 记录表"""
        vd = self.getJqData(name,mon,year)
        # 主数据
        df=pd.DataFrame(vd["kq/CHECKINOUT@考情记录"])
        chekdf = df.apply( self._标记一行 ,axis=1)
        # ---
        self._更新班次(chekdf)
        chekdf = chekdf[chekdf["班次"] != "空"]
        
        
        chekdf = self.getJqData(name,mon,year)
        
        # 创建日历
        r = self._出勤表v1(year,mon)
        rdf =  pd.DataFrame(r)
        # 合并两表
        result = pd.merge(
            rdf,
            chekdf,
            left_on=["日期", "阶段"],  # 左表关联字段
            right_on=["日期", "班次"],  # 右表关联字段
            how="left"  # LEFT JOIN
        )
        
        return result
    
    
    
    
